package br.com.srv.service;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import br.com.srv.config.ConfiguracaoSpring;
import br.com.srv.dao.DadosLidoDAO;
import br.com.srv.exception.FFServiceException;
import br.com.srv.util.DateHelper;

public class ClasseServicoImpl implements ClasseServico {
	
	private DadosLidoDAO dadosLidoDAO;
	private TratarPonto tratarPonto;
	
	
	String veiculoId;
	
	public ClasseServicoImpl() {
		dadosLidoDAO = (DadosLidoDAO)ConfiguracaoSpring.getBean(DadosLidoDAO.SERVICE_NAME);
		tratarPonto = new TratarPontoImpl();
	}
	
	public List<Map<String, String>> processarCoordenadas(String mensagem) throws Exception {
		
		List<Map<String, String>> listaComando = new ArrayList<Map<String,String>>();

		try {
			//01#03833.0490W#0346.5874S#0.03#-127#090708 182838
			String mensageArray[] = mensagem.split("#");
			
			String serial = mensageArray[0];
			String longitude = mensageArray[1];
			String latitude = mensageArray[2];
			String velocidade = mensageArray[3];
			String ignicao = mensageArray[4];
			String dataModulo = mensageArray[5];
			
			//Pegar parametros adicionais, como: Motorista, contador do guincho e etc.
			Map<String, String> paramAdicionais = new HashMap<String, String>();			
			for(int i = 6; i < mensageArray.length; i++) {
				String parametro[] = mensageArray[i].split(":");

 				String chave = parametro[0];
				String valor = parametro[1];

				//Se for código de motorista, decodificar.
				if (chave.equals("mot"))  {
					valor = converterCodigoRfid(valor);
				}
				
				//Esse if não é para ter, falar com o emerson para tirar esse "normal" e "dump"
				if (!valor.equals("normal") && !valor.equals("dump")) {
					paramAdicionais.put(chave, valor);
				}
			}
			
			String distanciUltimoPonto = "0";
			
			//pegar id do veiculo
			if (veiculoId == null || veiculoId.equals("")) {
				veiculoId = getDadosLidoDAO().buscarVeiculoIdBySerial(serial);
				if (veiculoId.equals("")) {
					throw new FFServiceException(null, "Não existe veiculo cadastrado com serial: " + serial);
				}
			}
			
			longitude = tratarCoordenada(longitude);
			latitude = tratarCoordenada(latitude);
			dataModulo = tratarData(dataModulo);
			
			//inserir ponto
			receberPonto(latitude, longitude, velocidade, ignicao, dataModulo, distanciUltimoPonto, veiculoId, paramAdicionais);
			
			//buscar comandos que devem ser enviados ao módulo
			listaComando = buscarComandosPendentes(serial);
			
		} catch (Exception e) {
			e.printStackTrace();
			throw new FFServiceException(e, "Erro na formação da mensagem");
		}
		
		return listaComando;
		
	}

	public String converterCodigoRfid(String valor) {
		
		String resultado = "";
		
		String array[] = valor.split(",");
		
		for (String vez : array) {
			byte b = (byte)vez.codePointAt(0);
			resultado += Integer.toHexString(vez.codePointAt(0)).substring(1);
		}
		
		System.out.println("[conversao: " + resultado + "]");
		return resultado;
	}

	public static String tratarData(String dataModulo) throws ParseException {
		
		Date data2 = DateHelper.parseDate(DateHelper.PATTERN_FROM_MODULE, dataModulo);
		dataModulo = DateHelper.parseString(data2);
		
		return dataModulo;
	}

	/**
	 * Método para tratar a coordenada e coloca-la no formato correto.
	 * W significa +
	 * S significa -
	 * @param coordenada String com a coordenada
	 * @return String com a coordenada no formato correto.
	 */
	public String tratarCoordenada(String coordenada) {
		
		char polaridade = coordenada.toUpperCase().charAt(coordenada.length() - 1);
		coordenada = coordenada.substring(0, coordenada.length()-1);
		
		//01#03833.0490W#0346.5874S#0.03#-127#090708 182838
		String a[] = coordenada.split("\\.");
		String primeiraParte = a[0];
		String aux = "";
		for(int i = 0; i < primeiraParte.length() - 2; i++) {
			aux += primeiraParte.charAt(i);
		}
		
		String aux2 = primeiraParte.substring(primeiraParte.length()- 2, primeiraParte.length()) + ".";
		
		coordenada = aux + "." + aux2 + a[1];
		
		String ar[] = {aux, aux2 + a[1], String.valueOf(polaridade)};
		
		if (ar != null) {

			Double decdeg = new Double(ar[0]) + (new Double(ar[1]) / 60);
			
			if ( (ar[2].equalsIgnoreCase(ClasseServico.NEGATIVO)) ||
					(ar[2].equalsIgnoreCase(ClasseServico.POSITIVO))) {
				decdeg = -decdeg;
			}

			long l = (Math.round(100000*decdeg)/100000);
			
			Long t = (Math.round(100000*decdeg)%100000);
			
			if(Long.signum(t) == (-1)) {
				t *= -1;
			}
			
			coordenada = String.valueOf(l);
			coordenada += "."+String.valueOf(t); 

		} else {
			System.out.println(false);
		}
		
		return coordenada;
	}

	private void receberPonto(String latitude, String longitude,
			String velocidade, String ignicao, String dataModulo,
			String distanciUltimoPonto, String veiculoId, Map<String, String> paramAdicionais)
			throws FFServiceException {
		
		Map<String, String> pontoMaisProximo = getTratarPonto().pegarPontoMaisPróximo(longitude, latitude);
		
		//verificar se é a primeira transmissão
		Map<String, String> ultimoDadoLido = getDadosLidoDAO().primeiraVezUltimoDadoLido(veiculoId);					
		
		if (ultimoDadoLido == null) {
			//inserir ultimo dado lido
			getDadosLidoDAO().inserirUltimoDadoLido(veiculoId, dataModulo, longitude, latitude,
					velocidade, ignicao, pontoMaisProximo.get("ID"), pontoMaisProximo.get("DISTANCIA"),
					distanciUltimoPonto, paramAdicionais);
		} else {
			//pegar distancia do ultimo ponto
			distanciUltimoPonto = tratarPonto.distanciaEntrePontos(
					longitude, latitude, ultimoDadoLido.get("LNG"), ultimoDadoLido.get("LAT")).toString();
			
			//atualizar ultimo dado lido								
			getDadosLidoDAO().atualizarUltimoDadoLido(veiculoId, dataModulo, longitude, latitude,
					velocidade, ignicao, pontoMaisProximo.get("ID"), pontoMaisProximo.get("DISTANCIA"),
					distanciUltimoPonto, paramAdicionais);
		}
	}

	private List<Map<String, String>> buscarComandosPendentes(String serial) throws FFServiceException {
		
		List<Map<String, String>> listaComandos = getDadosLidoDAO().buscarComandosNaoEnviadosPorVeiculoId(serial);
		
		return listaComandos;
	}
	
	public void setarComandoComoEnviado(String comandoId) throws FFServiceException {
		getDadosLidoDAO().setarComandoComoEnviado(comandoId);
	}
	
	public DadosLidoDAO getDadosLidoDAO() {
		return dadosLidoDAO;
	}

	public void setDadosLidoDAO(DadosLidoDAO dadosLidoDAO) {
		this.dadosLidoDAO = dadosLidoDAO;
	}

	public TratarPonto getTratarPonto() {
		return tratarPonto;
	}

	public void setTratarPonto(TratarPonto tratarPonto) {
		this.tratarPonto = tratarPonto;
	}
	
}
